Skip to content

feat(linearagent): Linear Agent Session webhook types + API client (RIG-2717 T1/T2) - #638

Merged
mattwilkinsonn merged 3 commits into
mainfrom
compass-server/rig-2717-store
Aug 27, 2026
Merged

feat(linearagent): Linear Agent Session webhook types + API client (RIG-2717 T1/T2)#638
mattwilkinsonn merged 3 commits into
mainfrom
compass-server/rig-2717-store

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

This PR is part of a stack containing 2 PRs:

  1. main
  2. "feat(store): fold linear_agent_sessions into 0001, no incremental migration (RIG-2717)" (this PR)
  3. feat(server): per-deployment public URL + deep-link builder (RIG-2717 T5) #639

Persistence for the Linear Agent Session responder — folded into the single baseline migration per Matt's ruling on this PR.

  • linear_agent_sessions table folds directly into 0001_init.sql (no incremental 0002): Compass isn't deployed yet, so there's no data to preserve and no reason to ship an incremental migration. The association row is keyed on the Linear session id; there's no dedup column — dedup is the comms rail's client_request_id.
  • Store surface: UpsertLinearAgentSession (ON CONFLICT DO NOTHING, created=false on replay), LinearAgentSession lookup, and AuthoredArtifactByCoordinate (the by-coordinate ownership read the router needs).
  • Generalizes the reserved system-account seed to a shared ensureSystemSubtypeAccount, seeds @linear as a second system-subtype account, and reserves the linear handle against user/agent registration.

pgtest-covered: upsert/replay/lookup, by-coordinate hit/miss, @linear idempotent seed + structural exclusions + reserved-handle guard.

Spec-impact: none. Refs RIG-2717
Co-authored-by: Matt Wilkinson matt@rigel.build

@linear-code

linear-code Bot commented Aug 26, 2026

Copy link
Copy Markdown

RIG-2717

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-server-rig-2717-stor.compass-eng-docs.pages.dev

Deployed from compass-server/rig-2717-store at 9e905be.

@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-linearagent branch from 15102f9 to 012b113 Compare August 26, 2026 04:01
@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-store branch from 276657c to dd0e7e7 Compare August 26, 2026 04:02
Base automatically changed from compass-server/rig-2717-linearagent to main August 26, 2026 04:23
@rigel-mintaka rigel-mintaka changed the title feat(store): linear_agent_sessions table + @linear bridge seed (RIG-2717 T3/T3a) feat(linearagent): Linear Agent Session webhook types + API client (RIG-2717 T1/T2) Aug 26, 2026
rigel-mintaka and others added 3 commits August 27, 2026 14:03
…IG-2717 T1/T2)

New go/internal/linearagent package for the Linear Agent Session responder:

- webhook.go (T1): SessionEvent envelope (AgentSessionEventWebhookPayload
  shape), ParseSessionEvent, VerifySignature (constant-time HMAC-SHA256 over
  the raw body, false on hex-decode error), CheckTimestamp (bidirectional
  skew on the ms-epoch webhookTimestamp).
- client.go (T2): client-credentials TokenSource (in-memory cache,
  singleflight-coalesced re-mint, pinned scope), and the Client emitter
  wrapping agentActivityCreate (the thought ack) + agentSessionUpdate (the
  external-URL deep link), re-minting once and retrying once on 401.

Pure/unit-tested against httptest; no HTTP handler, store, or dispatcher yet
(sibling tasks). Builds against the frozen record
docs/designs/product/compass-linear-agent-responder/design.md.

Ref: RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>
…717 T3/T3a)

Persistence for the Linear Agent Session responder:

- T3: new 0002_linear_agent_sessions migration (association row keyed on the
  Linear session id; no dedup column — dedup is the comms rail's
  client_request_id), UpsertLinearAgentSession (ON CONFLICT DO NOTHING,
  created=false on replay) + LinearAgentSession lookup, and
  AuthoredArtifactByCoordinate (by-coordinate ownership read the router needs).
- T3a: generalize the reserved system-account seed to a shared
  ensureSystemSubtypeAccount, add EnsureLinearBridgeAccount seeding @linear as
  a second system-subtype account, and reserve the 'linear' handle against
  user/agent registration.

pgtest-covered (upsert/replay/lookup, by-coordinate hit/miss, @linear
idempotent seed + structural exclusions + reserved-handle guard).

Ref: RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ration (RIG-2717)

Matt's ruling on #638: collapse the linear_agent_sessions table into the single existing 0001_init.sql migration rather than shipping an incremental 0002 — Compass isn't deployed yet, so there's no data to migrate and no reason for a versioned increment.

Moves the CREATE TABLE linear_agent_sessions into 0001_init.sql (adapting the file-header comment), deletes 0002_linear_agent_sessions.sql, and updates the pgtest header comment that named the '0002 table'. Pure DDL relocation — no backfill (the table carried none), no schema shape change; the migration loader embeds migrations/*.sql and enforces a contiguous 1..N sequence, so a single 0001 stays valid.

Refs RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>
@rigel-mintaka
rigel-mintaka force-pushed the compass-server/rig-2717-store branch from dd0e7e7 to 9e905be Compare August 27, 2026 18:06
@mattwilkinsonn
mattwilkinsonn merged commit 574025c into main Aug 27, 2026
49 checks passed
@mattwilkinsonn
mattwilkinsonn deleted the compass-server/rig-2717-store branch August 27, 2026 21:24
mattwilkinsonn added a commit that referenced this pull request Aug 27, 2026
… T5) (#639)

* feat(linearagent): Linear Agent Session webhook types + API client (RIG-2717 T1/T2)

New go/internal/linearagent package for the Linear Agent Session responder:

- webhook.go (T1): SessionEvent envelope (AgentSessionEventWebhookPayload
  shape), ParseSessionEvent, VerifySignature (constant-time HMAC-SHA256 over
  the raw body, false on hex-decode error), CheckTimestamp (bidirectional
  skew on the ms-epoch webhookTimestamp).
- client.go (T2): client-credentials TokenSource (in-memory cache,
  singleflight-coalesced re-mint, pinned scope), and the Client emitter
  wrapping agentActivityCreate (the thought ack) + agentSessionUpdate (the
  external-URL deep link), re-minting once and retrying once on 401.

Pure/unit-tested against httptest; no HTTP handler, store, or dispatcher yet
(sibling tasks). Builds against the frozen record
docs/designs/product/compass-linear-agent-responder/design.md.

Ref: RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>

* feat(store): linear_agent_sessions table + @linear bridge seed (RIG-2717 T3/T3a)

Persistence for the Linear Agent Session responder:

- T3: new 0002_linear_agent_sessions migration (association row keyed on the
  Linear session id; no dedup column — dedup is the comms rail's
  client_request_id), UpsertLinearAgentSession (ON CONFLICT DO NOTHING,
  created=false on replay) + LinearAgentSession lookup, and
  AuthoredArtifactByCoordinate (by-coordinate ownership read the router needs).
- T3a: generalize the reserved system-account seed to a shared
  ensureSystemSubtypeAccount, add EnsureLinearBridgeAccount seeding @linear as
  a second system-subtype account, and reserve the 'linear' handle against
  user/agent registration.

pgtest-covered (upsert/replay/lookup, by-coordinate hit/miss, @linear
idempotent seed + structural exclusions + reserved-handle guard).

Ref: RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>

* feat(store): fold linear_agent_sessions into 0001, no incremental migration (RIG-2717)

Matt's ruling on #638: collapse the linear_agent_sessions table into the single existing 0001_init.sql migration rather than shipping an incremental 0002 — Compass isn't deployed yet, so there's no data to migrate and no reason for a versioned increment.

Moves the CREATE TABLE linear_agent_sessions into 0001_init.sql (adapting the file-header comment), deletes 0002_linear_agent_sessions.sql, and updates the pgtest header comment that named the '0002 table'. Pure DDL relocation — no backfill (the table carried none), no schema shape change; the migration loader embeds migrations/*.sql and enforces a contiguous 1..N sequence, so a single 0001 stays valid.

Refs RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>

* feat(server): per-deployment public URL + deep-link builder (RIG-2717 T5)

Add ServeConfig.PublicURL (--public-url flag / $COMPASS_PUBLIC_URL,
flag->env->default https://compass.rigel.build), and deepLinkFor(base,
channelID) building the 'Open in Compass' deep link to a Manager's home
channel (the UI hash route), with requirePublicURL as the legible boot guard
for a Linear-webhook-consuming deploy. Threaded through cmd/compass-server
(the server entrypoint) — not cmd/compass (the operator CLI, which does no
server construction).

Ref: RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>

* feat(server): no default public URL — managed host is not a repo concern (RIG-2717)

Matt's ruling on #639: don't default --public-url to the managed-service host (https://compass.rigel.build). That host is where the managed deployment lives, which never lives in this repo; baking it as the fallback means a self-host/dev deploy that forgets the flag silently emits deep links to the managed host.

Removes the defaultPublicURL constant; PublicURL now resolves from --public-url then $COMPASS_PUBLIC_URL with no default (empty when unset). The existing requirePublicURL boot guard already rejects an empty base for a webhook-consuming deploy and yields relative fragments for socket-only local — so no-default is the right shape (a dummy non-empty URL would instead DEFEAT that guard). Updates the flag help + the ServeConfig/boot-log/boot-guard doc comments, and neutralizes the managed host out of deeplink_test.go's sample URLs.

Refs RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>

* docs(server): drop vestigial managed-default clause from firstNonEmpty doc (RIG-2717)

Review finding (#639, low): after removing the managed default, firstNonEmpty's doc comment still described a 'where a managed default follows, flag-then-env-then-default' precedence that no remaining caller uses (every caller is flag-then-env only) — muddying the very ruling this branch implements. Simplified to describe only the flag-then-env precedence in use. Comment-only.

Refs RIG-2717
Co-authored-by: Matt Wilkinson <matt@rigel.build>

---------

Co-authored-by: Matt Wilkinson <matt@rigel.build>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants